package it.unipg.bipod.web;

import it.unipg.bipod.applicationLogic.*;
import it.unipg.bipod.dataModel.*;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Comparator;

/**
 * DocenteBandiBean gestisce le attivita' del docente collegate alla gestione dei bandi.<br>
 * Permette di consultare l'elenco dei bandi attivi, gli insegnamenti appartenenti a ciascun
 * bando e di inoltrare o cancellare richieste di assegnamento.<br>
 * Sono presenti due sottoclassi pubbliche: BandoBean e InsegnamentoBean.<br>
 * Eventuali messaggi o errori vengono segnalati mediante i metodi forniti da DefaultBean.
 * 
 * @author Lorenzo Porzi
 * @see DefaultBean
 * @see DocenteBean
 */
public class DocenteBandiBean extends DefaultBean {
	private DocenteApplication application; // L'oggetto application che gestisce questa sessione
	private BandoBean bandoCorrente; // Il bando correntemente visualizzato
	
	private BandoBean[] bandi; // I bandi visualizzati
	
	/**
	 * Costruisce un DocenteBandiBean associato alla DocenteApplication fornita.
	 * 
	 * @param application la DocenteApplication da associare a questo DocenteBandiBean.
	 */
	public DocenteBandiBean(DocenteApplication application) {
		super();
		
		bandoCorrente = null;
		this.application = application;
		
		// Carica i bandi
		try {
			// Recupera i bandi
			Bando[] bandi = application.getBandi();
			
			// Li ordina per data di pubblicazione
			Arrays.sort(bandi, new Comparator<Bando>() {
				public int compare(Bando b1, Bando b2) {
					return b2.getDataPubblicazione().compareTo(b1.getDataPubblicazione());
				}
			});
			
			// Incapsula i bandi
			this.bandi = new BandoBean[bandi.length];
			for (int i = 0; i < bandi.length; ++i)
				this.bandi[i] = new BandoBean(bandi[i]);
		} catch (ApplicationException e) {
			BandoBean[] vuoto = {};
			this.bandi = vuoto;
		}
	}
	
	/* ----------------------------------
	 * Setters e getters per le proprietà
	 * ---------------------------------- */
	
	/**
	 * Imposta il bando attualmente visualizzato in dettaglio.
	 * 
	 * @param bandoCorrente il bando da visualizzare in dettaglio.
	 */
	public void setBandoCorrente(BandoBean bandoCorrente) {
		this.bandoCorrente = bandoCorrente;
	}

	/**
	 * Ritorna il bando attualmente visualizzato in dettaglio.
	 * 
	 * @return il bando visualizzato in dettaglio.
	 */
	public BandoBean getBandoCorrente() {
		return bandoCorrente;
	}
	
	/* --------------------------------
	 * Metodi per l'estrazione dei dati
	 * -------------------------------- */
	
	/**
	 * Restituisce l'elenco dei bandi attivi.
	 * 
	 * @return un array di BandoBean in cui ogni elemento è associato ad un bando attivo.
	 */
	public BandoBean[] getBandi() {
		return bandi;
	}
	
	/**
	 * Restituisce il numero di bandi attivi.
	 * 
	 * @return il numero di bandi attivi.
	 */
	public int getNumeroBandi() {
		return bandi.length;
	}
	
	/* -----------
	 * Sottoclassi
	 * ----------- */

	/**
	 * BandoBean incapsula un bando fornendo alcune funzionalita' aggiuntive.<br>
	 * Permette di recuperare l'elenco degli insegnamenti appartenenti a questo bando
	 * e fornisce il metodo di navigazione vediBando().
	 * 
	 * @author Lorenzo Porzi
	 *
	 */
	public class BandoBean {
		private Bando bando; // Il bando incapsulato
		private InsegnamentoBean[] insegnamenti; // Gli insegnamenti del bando
		private InsegnamentoBean ins;
		
		private int operazioneInCorso;
		
		/**
		 * Costruisce un BandoBean associato ad un Bando.<br>
		 * Carica immediatamente la lista degli insegnamenti associati al bando.
		 * 
		 * @param bando il Bando da associare a questo oggetto.
		 */
		public BandoBean(Bando bando) {
			this.setBando(bando);
			
			try {
				InsegnamentoCorso[] insegnamenti = application.getInsegnamenti(bando);
				
				this.insegnamenti = new InsegnamentoBean[insegnamenti.length];
				for (int i = 0; i < insegnamenti.length; ++i)
					this.insegnamenti[i] = new InsegnamentoBean(insegnamenti[i]);
				
			} catch (ApplicationException e) {
				InsegnamentoBean[] vuoto = {};
				this.insegnamenti = vuoto;
			}
			
			// Nessuna operazione in corso
			operazioneInCorso = 0;
			
			// Nessun insegnamento selezionato
			ins = null;
		}
		
		/* ----------------------------------
		 * Setters e getters per le proprietà
		 * ---------------------------------- */

		public void setBando(Bando bando) {
			this.bando = bando;
		}

		public Bando getBando() {
			return bando;
		}
		
		public int getOperazioneInCorso() {
			return operazioneInCorso;
		}
		
		public void setOperazioneInCorso(int operazioneInCorso) {
			this.operazioneInCorso = operazioneInCorso; 
		}
		
		public InsegnamentoBean getInsegnamentoSelezionato() {
			return ins;
		}
		
		public void setInsegnamentoSelezionato(InsegnamentoBean ins) {
			this.ins = ins;
		}
		
		/* --------------------------------
		 * Metodi per l'estrazione dei dati
		 * -------------------------------- */
		
		public String getDataPubblicazione() {
			Format dateFormat = new SimpleDateFormat("dd/MM/yyyy");
			return dateFormat.format(bando.getDataPubblicazione());
		}
		
		public String getDataScadenza() {
			Format dateFormat = new SimpleDateFormat("dd/MM/yyyy");
			return dateFormat.format(bando.getDataScadenza());
		}
		
		/**
		 * Restituisce l'elenco degli insegnamenti appartenenti a questo bando.
		 * 
		 * @return un array di InsegnamentoBean in cui ogni elemento incapsula un insegnamento
		 * di questo bando.
		 */
		public InsegnamentoBean[] getInsegnamenti() {
			return insegnamenti;
		}
		
		/**
		 * Restituisce il numero di insegnamenti appartenenti a questo bando.
		 * 
		 * @return il numero di insegnamenti di questo bando.
		 */
		public int getNumeroInsegnamenti() {
			return insegnamenti.length;
		}
		
		/* ---------------------
		 * Metodi di navigazione
		 * --------------------- */
		
		/**
		 * Metodo di navigazione: imposta questo come bando corrente e va alla pagina
		 * di dettaglio del bando.
		 * 
		 * @return "/pages/docente-dettaglio-bando"
		 */
		public String vediBando() {
			setBandoCorrente(this);
			
			return "/pages/docente-dettaglio-bando";
		}
	}
	
	/**
	 * InsegnamentoBean incapsula un insegnamento fornendo alcune funzionalita' aggiuntive.<br>
	 * Permette di: controllare se il docente ha già fatto richiesta per questo insegnamento,
	 * inoltrare una richiesta di assegnamento oppure cancellarla.
	 * 
	 * @author Lorenzo Porzi
	 *
	 */
	public class InsegnamentoBean {
		private InsegnamentoCorso insegnamento; // L'insegnamento incapsulato
		
		/**
		 * Costruisce un InsegnamentoBean associato ad un Insegnamento.
		 * 
		 * @param insegnamento l'Insegnamento da associare a questo oggetto.
		 */
		public InsegnamentoBean(InsegnamentoCorso insegnamento) {
			this.insegnamento = insegnamento;
		}
		
		/* ----------------------------------
		 * Setters e getters per le proprietà
		 * ---------------------------------- */

		public void setInsegnamento(InsegnamentoCorso insegnamento) {
			this.insegnamento = insegnamento;
		}

		public InsegnamentoCorso getInsegnamento() {
			return insegnamento;
		}
		
		/**
		 * Controlla se il docente ha fatto richiesta per questo insegnamento.
		 * 
		 * @return {@code true} se ha gia' fatto richiesta, {@code false} altrimenti.
		 */
		public boolean getRichiesto() {
			try {
				Richiesta[] ric = application.getRichiesteEffettuate();
				for (Richiesta r : ric)
					if (r.getInsegnamento() == insegnamento.getIdInsegnamento())
						return true;
				
				return false;
			} catch (ApplicationException e) {
				return false;
			}
		}
		
		/* ---------------------
		 * Metodi di navigazione
		 * --------------------- */
		
		/**
		 * Conferma la memorizzazione di una richiesta di assegnamento.<br> 
		 * Questo metodo utilizza le seguenti proprieta' di presentation.ini:
		 * <ul>
		 *   <li><b>msgNuovaRichiestaRiuscita</b>: il messaggio visualizzato quando la nuova richiesta riesce.</li>
		 *   <li><b>msgErroreNuovaRichiesta</b>: il messaggio visualizzato quando la nuova richiesta fallisce.</li>
		 * </ul>
		 */
		public void confermaRichiesta() {
			bandoCorrente.operazioneInCorso = 0;
			bandoCorrente.ins = null;
			
			try {
				application.nuovaRichiesta(insegnamento.getInsegnamento());
				
				addInfoMessage(getSettings().getProperty("msgNuovaRichiestaRiuscita").replaceAll("<0>", insegnamento.getNome()));
			} catch (ApplicationException e) {
				addWarnMessage(getSettings().getProperty("msgErroreNuovaRichiesta"));
			}
		}
		
		/**
		 * Annulla l'invio della richiesta in corso.
		 */
		public void annullaRichiesta() {
			bandoCorrente.operazioneInCorso = 0;
			bandoCorrente.ins = null;
		}
		
		/**
		 * Inoltra una richiesta di assegnamento per questo insegnamento.<br>
		 * Prima dell'effettivo invio viene visualizzata una pagina di conferma.
		 */
		public void richiedi() {
			bandoCorrente.operazioneInCorso = 1;
			bandoCorrente.ins = this;
		}
		
		/**
		 * Conferma la cancellazione della richiesta di assegnamento per questo insegnamento.<br>
		 * Questo metodo utilizza le seguenti proprieta' di presentation.ini:
		 * <ul>
		 *   <li><b>msgCancellaRichiestaRiuscita</b>: il messaggio visualizzato quando la cancellazione riesce.</li>
		 *   <li><b>msgErroreCancellaRichiesta</b>: il messaggio visualizzato quando la cancellazione fallisce.</li>
		 * </ul>
		 */
		public void confermaCancellazione() {
			bandoCorrente.operazioneInCorso = 0;
			bandoCorrente.ins = null;
			
			try {
				application.cancellaRichiesta(insegnamento.getInsegnamento());
				
				addInfoMessage(getSettings().getProperty("msgCancellaRichiestaRiuscita"));
			} catch (ApplicationException e) {
				addWarnMessage(getSettings().getProperty("msgErroreCancellaRichiesta"));
			}
		}
		
		/**
		 * Annulla la cancellazione delle richiesta di assegnamento in corso.
		 */
		public void annullaCancellazione() {
			bandoCorrente.operazioneInCorso = 0;
			bandoCorrente.ins = null;
		}
		
		/**
		 * Cancella la richiesta di assegnamento per questo insegnamento.<br>
		 * Prima dell'effettiva cancellazione viene visualizzata una pagina di conferma.
		 */
		public void cancellaRichiesta() {
			bandoCorrente.operazioneInCorso = 2;
			bandoCorrente.ins = this;
		}
	}
}
